import * as XLSX from 'xlsx';

/**
 * Excel日期解析工具类
 * 处理Excel中的日期序列号转换为JavaScript Date对象
 */
export class ExcelDateUtil {
  /**
   * 将Excel日期序列号转换为Date对象
   * @param value Excel中的日期值（可能是序列号或日期字符串）
   * @returns Date对象
   */
  static parseExcelDate(value: any): Date {
    if (!value) {
      throw new Error('日期值不能为空');
    }

    // 如果已经是Date对象，直接返回
    if (value instanceof Date) {
      return value;
    }

    const stringValue = String(value).trim();
    
    // 检查是否为Excel日期序列号（纯数字）
    if (this.isExcelSerialNumber(stringValue)) {
      return this.convertExcelSerialToDate(Number(stringValue));
    }

    // 尝试解析为标准日期格式，优先处理常见的Excel日期格式
    let parsedDate = this.parseChineseDateFormat(stringValue);
    
    if (!parsedDate) {
      // 如果自定义解析失败，尝试标准解析
      parsedDate = new Date(stringValue);
      if (isNaN(parsedDate.getTime())) {
        throw new Error(`无法解析的日期格式: ${stringValue}`);
      }
    }

    return parsedDate;
  }

  /**
   * 检查是否为Excel日期序列号
   * @param value 字符串值
   * @returns 是否为序列号
   */
  private static isExcelSerialNumber(value: string): boolean {
    // 检查是否为纯数字（包括小数）
    const numberPattern = /^\d+(\.\d+)?$/;
    if (!numberPattern.test(value)) {
      return false;
    }

    const num = Number(value);
    // Excel日期序列号范围：大于25569（1970-01-01）的数字更可能是Excel序列号
    // 这个阈值可以避免将普通数字误认为是日期序列号
    return num > 25569 && num <= 2958465;
  }

  /**
   * 将Excel序列号转换为Date对象
   * @param serialNumber Excel日期序列号
   * @returns Date对象
   */
  private static convertExcelSerialToDate(serialNumber: number): Date {
    try {
      // 使用XLSX库的内置方法解析Excel日期序列号
      const dateObj = XLSX.SSF.parse_date_code(serialNumber);
      
      // 创建Date对象，注意月份需要减1（JavaScript月份从0开始）
      const resultDate = new Date(
        dateObj.y,           // 年
        dateObj.m - 1,       // 月（减1）
        dateObj.d,           // 日
        dateObj.H || 0,      // 时
        dateObj.M || 0,      // 分
        dateObj.S || 0       // 秒
      );
      
      console.log(`🔢 Excel序列号转换: ${serialNumber} -> ${resultDate.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`);
      
      return resultDate;
    } catch (error) {
      console.error(`❌ Excel序列号转换失败: ${serialNumber}`, error);
      throw new Error(`Excel序列号转换失败: ${serialNumber}`);
    }
  }

  /**
   * 解析中文日期格式
   * @param dateString 日期字符串
   * @returns Date对象或null
   */
  private static parseChineseDateFormat(dateString: string): Date | null {
    if (!dateString) return null;
    
    // 替换中文分隔符和特殊字符
    let normalizedStr = dateString
      .replace(/年/g, '-')
      .replace(/月/g, '-')
      .replace(/日/g, ' ')
      .replace(/时/g, ':')
      .replace(/分/g, '')
      .replace(/秒/g, '')
      .replace(/\s+/g, ' ')
      .trim();

    // 支持的时间格式模式
    const patterns = [
      // 2025/6/27 03:00:00 或 2025/6/27 3:00:00
      {
        regex: /^(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{2}):(\d{2})$/,
        handler: (match) => {
          const [, year, month, day, hour, minute, second] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute),
            parseInt(second)
          );
        }
      },
      // 2025/6/27 3:00 或 2025/6/27 03:00
      {
        regex: /^(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}):(\d{2})$/,
        handler: (match) => {
          const [, year, month, day, hour, minute] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute)
          );
        }
      },
      // 2025-06-27 08-35-00 (带秒数的格式)
      {
        regex: /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2})-(\d{2})-(\d{2})$/,
        handler: (match) => {
          const [, year, month, day, hour, minute, second] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute),
            parseInt(second)
          );
        }
      },
      // 2025-06-27 08-35 (不带秒数的格式)
      {
        regex: /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2})-(\d{2})$/,
        handler: (match) => {
          const [, year, month, day, hour, minute] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute)
          );
        }
      },
      // 2025-06-27 08:35 或 2025-6-27 8:35
      {
        regex: /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{2})$/,
        handler: (match) => {
          const [, year, month, day, hour, minute] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute)
          );
        }
      },
      // 2025/6/27 或 2025-6-27 (只有日期)
      {
        regex: /^(\d{4})[-\/](\d{1,2})[-\/](\d{1,2})$/,
        handler: (match) => {
          const [, year, month, day] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            0,
            0
          );
        }
      },
      // mm/dd/yyyy hh:mm 格式
      {
        regex: /^(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}):(\d{2})$/,
        handler: (match) => {
          const [, month, day, year, hour, minute] = match;
          return new Date(
            parseInt(year),
            parseInt(month) - 1,
            parseInt(day),
            parseInt(hour),
            parseInt(minute)
          );
        }
      }
    ];

    // 尝试匹配所有模式
    for (const pattern of patterns) {
      const match = normalizedStr.match(pattern.regex);
      if (match) {
        const date = pattern.handler(match);
        if (!isNaN(date.getTime())) {
          console.log(`📅 日期解析成功: ${dateString} -> ${date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`);
          return date;
        }
      }
    }

    // 回退处理：使用Date构造函数
    let fallbackStr = normalizedStr
      .replace(/\//g, '-')
      .replace(/(\d{4}-\d{1,2}-\d{1,2})\s+(\d{1,2})-(\d{2})/, '$1 $2:$3')
      .replace(/(\d{1,2}:\d{2}):\d{2}/, '$1');

    const date = new Date(fallbackStr);
    if (!isNaN(date.getTime())) {
      console.log(`📅 回退解析成功: ${dateString} -> ${date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`);
      return date;
    }

    return null;
  }

  /**
   * 格式化日期为字符串
   * @param date Date对象
   * @param format 格式类型
   * @returns 格式化后的日期字符串
   */
  static formatDate(date: Date, format: 'iso' | 'local' | 'date-only' = 'iso'): string {
    switch (format) {
      case 'iso':
        return date.toISOString();
      case 'local':
        return date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
      case 'date-only':
        return date.toISOString().split('T')[0];
      default:
        return date.toISOString();
    }
  }
}